package wiki.xsx.core.bytecode.transformer;

import javassist.CtClass;
import javassist.bytecode.ClassFile;
import lombok.SneakyThrows;
import wiki.xsx.core.bytecode.enums.ExecuteType;
import wiki.xsx.core.bytecode.model.Annotations;

import java.util.Optional;

/**
 * 类注解转换器
 *
 * @author xsx
 * @date 2023/1/31
 * @since 1.8
 * <p>
 * Copyright (c) 2023 xsx All Rights Reserved.
 * easy-bytecode is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 * http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 * </p>
 */
public class ClassAnnotationTransformer extends AbstractAnnotationTransformer {

    /**
     * 执行类型
     */
    private final ExecuteType executeType;
    /**
     * 注解数组
     */
    private final Annotations[] annotations;

    /**
     * 有参构造
     *
     * @param isWrite     是否写入
     * @param fileDir     文件目录
     * @param executeType 执行类型
     * @param className   类名称
     * @param annotations 注解
     */
    public ClassAnnotationTransformer(Boolean isWrite, String fileDir, ExecuteType executeType, String className, Annotations... annotations) {
        super(isWrite, fileDir, className, null);
        this.executeType = executeType;
        this.annotations = Optional.ofNullable(annotations).orElse(new Annotations[0]);
    }

    /**
     * 执行转换
     *
     * @param ctClass ct类
     * @return 返回字节码
     */
    @SuppressWarnings("all")
    @SneakyThrows
    @Override
    public byte[] execute(CtClass ctClass) {
        ClassFile classFile = ctClass.getClassFile();
        switch (this.executeType) {
            // 新增或更新
            case ANNOTATION_CLASS_ADD_OR_UPDATE: {
                super.addOrUpdateAnnotation(classFile, classFile.getConstPool(), this.annotations).forEach(classFile::addAttribute);
                break;
            }
            // 移除
            case ANNOTATION_CLASS_REMOVE: {
                super.removeAnnotation(classFile, this.annotations);
                break;
            }
        }
        return ctClass.toBytecode();
    }
}
